/*********************************************************************
 * Copyright (C) 2002 Andrew Khan
 * <p>
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * <p>
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * <p>
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ***************************************************************************/

package jxl.biff;

import jxl.common.Assert;
import jxl.write.biff.File;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * A container for the list of fonts used in this workbook
 */
public class Fonts {
    /**
     * The list of fonts
     */
    private ArrayList fonts;

    /**
     * The default number of fonts
     */
    private static final int numDefaultFonts = 4;

    /**
     * Constructor
     */
    public Fonts() {
        fonts = new ArrayList();
    }

    /**
     * Adds a font record to this workbook.  If the FontRecord passed in has not
     * been initialized, then its font index is determined based upon the size
     * of the fonts list.  The FontRecord's initialized method is called, and
     * it is added to the list of fonts.
     *
     * @param f the font to add
     */
    public void addFont(FontRecord f) {
        if (!f.isInitialized()) {
            int pos = fonts.size();

            // Remember that the pos with index 4 is skipped
            if (pos >= 4) {
                pos++;
            }

            f.initialize(pos);
            fonts.add(f);
        }
    }

    /**
     * Used by FormattingRecord for retrieving the fonts for the
     * hardcoded styles
     *
     * @param index the index of the font to return
     * @return the font with the specified font index
     */
    public FontRecord getFont(int index) {
        // remember to allow for the fact that font index 4 is not used
        if (index > 4) {
            index--;
        }

        return (FontRecord) fonts.get(index);
    }

    /**
     * Writes out the list of fonts
     *
     * @param outputFile the compound file to write the data to
     * @exception IOException
     */
    public void write(File outputFile) throws IOException {
        Iterator i = fonts.iterator();

        FontRecord font = null;
        while (i.hasNext()) {
            font = (FontRecord) i.next();
            outputFile.write(font);
        }
    }

    /**
     * Rationalizes all the fonts, removing any duplicates
     *
     * @return the mappings between new indexes and old ones
     */
    IndexMapping rationalize() {
        IndexMapping mapping = new IndexMapping(fonts.size() + 1);
        // allow for skipping record 4

        ArrayList newfonts = new ArrayList();
        FontRecord fr = null;
        int numremoved = 0;

        // Preserve the default fonts
        for (int i = 0; i < numDefaultFonts; i++) {
            fr = (FontRecord) fonts.get(i);
            newfonts.add(fr);
            mapping.setMapping(fr.getFontIndex(), fr.getFontIndex());
        }

        // Now do the rest
        Iterator it = null;
        FontRecord fr2 = null;
        boolean duplicate = false;
        for (int i = numDefaultFonts; i < fonts.size(); i++) {
            fr = (FontRecord) fonts.get(i);

            // Compare to all the fonts currently on the list
            duplicate = false;
            it = newfonts.iterator();
            while (it.hasNext() && !duplicate) {
                fr2 = (FontRecord) it.next();
                if (fr.equals(fr2)) {
                    duplicate = true;
                    mapping.setMapping(fr.getFontIndex(),
                            mapping.getNewIndex(fr2.getFontIndex()));
                    numremoved++;
                }
            }

            if (!duplicate) {
                // Add to the new list
                newfonts.add(fr);
                int newindex = fr.getFontIndex() - numremoved;
                Assert.verify(newindex > 4);
                mapping.setMapping(fr.getFontIndex(), newindex);
            }
        }

        // Iterate through the remaining fonts, updating all the font indices
        it = newfonts.iterator();
        while (it.hasNext()) {
            fr = (FontRecord) it.next();
            fr.initialize(mapping.getNewIndex(fr.getFontIndex()));
        }

        fonts = newfonts;

        return mapping;
    }
}
